﻿// <copyright file="WP7DataCollector.cs" company="Microsoft Corporation">
// Copyright (c) 2010 Microsoft Corporation All Rights Reserved
// </copyright>
// <author>Michael S. Scherotter</author>
// <email>mischero@microsoft.com</email>
// <date>2010-07-19</date>
// <summary>Windows Phone 7 Data collector</summary>

namespace Microsoft.WebAnalytics
{
    using System;
    using System.ComponentModel.Composition;
    using System.Globalization;
    using System.Windows;
    using System.Xml;
    using Microsoft.WebAnalytics.Contracts;

    /// <summary>
    /// Data collector for Windows Phone 7
    /// </summary>
    [Export(typeof(IDataCollector))]
    public class WP7DataCollector : DataCollector, IDisposable
    {
        #region Fields
        /// <summary>
        /// The ProductID application from the Windows Phone App Manifest
        /// </summary>
        private string productId;
        #endregion

        #region Constructors
        /// <summary>
        /// Initializes a new instance of the WP7DataCollector class.
        /// </summary>
        /// <remarks>this constructor is called by MEF</remarks>
        public WP7DataCollector()
        {
        }
        #endregion

        #region Properties
        /// <summary>
        /// Gets the App.ProductID from the Windows Phone WMAppManifest
        /// </summary>
        private string ProductId
        {
            get
            {
                if (string.IsNullOrEmpty(this.productId))
                {
                    this.productId = GetAppAttribute("ProductID");
                }

                return this.productId;
            }
        }

        #endregion

        #region Methods
        /// <summary>
        /// Log an event
        /// </summary>
        /// <param name="logEvent">the event to log</param>
        /// <remarks>This is exported via MEF</remarks>
        [Export("Log")]
        public new void Log(AnalyticsEvent logEvent)
        {
            base.Log(logEvent);
        }

        /// <summary>
        /// Dispose of the GeoCoordinateWatcher
        /// </summary>
        public void Dispose()
        {
            this.Dispose(true);

            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// Dispose of the watcher
        /// </summary>
        /// <param name="managedAndNative">dispose of both managed and native</param>
        protected virtual void Dispose(bool managedAndNative)
        {
            ////if (this.watcher != null)
            ////{
            ////    this.watcher.Dispose();

            ////    this.watcher = null;
            ////}
        }

        ////public bool IsLocationTrackingEnabled
        ////{
        ////    get
        ////    {
        ////        return this.isLocationTrackingEnabled;
        ////    }
        ////    set
        ////    {
        ////        this.isLocationTrackingEnabled = value;

        ////        if (this.isLocationTrackingEnabled)
        ////        {
        ////            if (this.watcher == null)
        ////            {
        ////                this.watcher = new GeoCoordinateWatcher(GeoPositionAccuracy.Default)
        ////                {
        ////                    MovementThreshold = 20
        ////                };

        ////                this.watcher.Start();
        ////            }
        ////        }
        ////        else
        ////        {
        ////            if (this.watcher != null)
        ////            {
        ////                this.watcher.Stop();

        ////                this.watcher.Dispose();

        ////                this.watcher = null;
        ////            }
        ////        }
        ////    }
        ////}

        /// <summary>
        /// Initialize the events and properties
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Object is disposed in Dispose method.")]
        protected override void OnInitialize()
        {
            this.Title = GetAppAttribute("Title");

            this.Version = GetAppAttribute("Version");

            var root = Application.Current.RootVisual as Microsoft.Phone.Controls.PhoneApplicationFrame;

            if (root != null)
            {
                root.Navigated += new System.Windows.Navigation.NavigatedEventHandler(this.OnRootNavigated);

                root.FragmentNavigation += new System.Windows.Navigation.FragmentNavigationEventHandler(this.OnRootFragmentNavigation);
            }
        }

        /// <summary>
        /// attach phone-specific data to each event
        /// </summary>
        /// <param name="logEvent">the logEvent</param>
        protected override void OnLog(AnalyticsEvent logEvent)
        {
            logEvent.EventArgs.Add(new Microsoft.WebAnalytics.Data.PropertyValue { PropertyName = "ProductID", Value = this.ProductId });
            logEvent.DocumentUri = new Uri(this.Title, UriKind.Relative);

            ////if (this.IsLocationTrackingEnabled)
            ////{
            ////    if (this.watcher == null)
            ////    {
            ////        this.OnInitialize();
            ////    }

            ////    if (this.watcher.Status == GeoPositionStatus.Ready)
            ////    {
            ////        var location = string.Format(
            ////            CultureInfo.InvariantCulture,
            ////            "{0},{1}",
            ////            this.watcher.Position.Location.Latitude,
            ////            this.watcher.Position.Location.Longitude);

            ////        logEvent.EventArgs.Add(new Data.PropertyValue { PropertyName = "Location", Value = location });
            ////    }
            ////}
        }

        #endregion

        #region Implementation

        /// <summary>
        /// Gets an attribute from the Windows Phone App Manifest App element
        /// </summary>
        /// <param name="attributeName">the attribute name</param>
        /// <returns>the attribute value</returns>
        private static string GetAppAttribute(string attributeName)
        {
            string appManifestName = "WMAppManifest.xml";
            string appNodeName = "App";

            var settings = new XmlReaderSettings();
            settings.XmlResolver = new XmlXapResolver();

            using (XmlReader rdr = XmlReader.Create(appManifestName, settings))
            {
                rdr.ReadToDescendant(appNodeName);
                if (!rdr.IsStartElement())
                {
                    throw new System.FormatException(appManifestName + " is missing " + appNodeName);
                }

                return rdr.GetAttribute(attributeName);
            }
        }

        /// <summary>
        /// Root Fragment Navigation event handler
        /// </summary>
        /// <param name="sender">the NavigationService</param>
        /// <param name="e">the fragment navigation event arguments</param>
        private void OnRootFragmentNavigation(object sender, System.Windows.Navigation.FragmentNavigationEventArgs e)
        {
            var logEvent = new AnalyticsEvent
            {
                HitType = Data.HitType.PageView,
                Name = "FragmentNavigation",
                ObjectType = sender.GetType().Name
            };

            this.Log(logEvent);
        }

        /// <summary>
        /// Root Navigated event handler
        /// </summary>
        /// <param name="sender"> the NavigationService</param>
        /// <param name="e">the navigation event arguments</param>
        private void OnRootNavigated(object sender, System.Windows.Navigation.NavigationEventArgs e)
        {
            var logEvent = new AnalyticsEvent
            {
                ActionValue = e.Uri.ToString(),
                HitType = Data.HitType.PageView,
                Name = "Navigated",
                ObjectType = sender.GetType().Name
            };

            this.Log(logEvent);
        }

        #endregion
    }
}
